

import java.io.FileWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class DbCompareTest {

    private static final String URL="jdbc:mysql://localhost:3306/bootstrap";
    private static final String newURL="jdbc:mysql://localhost:3306/newbootstap";
    private static final String NAME="trex";
    private static final String PASSWORD="test123456";
    //存储错误
    public static StringBuffer sbMessage=new StringBuffer();
    public static StringBuffer[] sb = { new StringBuffer(), new StringBuffer(),
            new StringBuffer(), new StringBuffer(), new StringBuffer(),
            new StringBuffer() };

    public static void main(String[] args) throws Exception {
        System.out.println("开始运行");
        compareTables(); // 比较数据库
        writeFile(); // 写入文件
        System.out.println("结束运行");
        System.out.println("结束运行");
    }


    //连接旧的数据库的
    public static Connection getOldTable() throws Exception{
        //1.加载驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //2.获得数据库的连接
        Connection conn = DriverManager.getConnection(URL, NAME, PASSWORD);
        //3.通过数据库的连接操作数据库，实现增删改查
        //Statement stmt = conn.createStatement();
        return  conn;
    }



    //连接新的数据库的
    public static Connection getNewTable() throws Exception{
        //1.加载驱动程序
        Class.forName("com.mysql.jdbc.Driver");
        //2.获得数据库的连接
        Connection conn = DriverManager.getConnection(newURL, NAME, PASSWORD);
        //3.通过数据库的连接操作数据库，实现增删改查
        //Statement stmt = conn.createStatement();
        return  conn;
    }

    /**
     * 获取库里面有哪些表
     */
    public static List<DatabaseTable> getDbTables(Connection connection) throws Exception{
        String   catalog          = null;
        String   schemaPattern    = null;
        String   tableNamePattern = null;
        String[] types            = null;
        List<DatabaseTable> tableNames=new ArrayList<DatabaseTable>();
        //从getTables()方法返回的ResultSet包含匹配 4 给定的参数 （其中全部为 null） 的表名称的列表。
        // 此ResultSet包含 10 个栏目，其中每个包含给定表的信息。带有索引 3 列包含表名称本身
        ResultSet result = connection.getMetaData().getTables(
                catalog, schemaPattern, tableNamePattern, types );
        while(result.next()) {
            String tableName = result.getString(3);

            //主键存入databaseTable
            // 适用mysql...获取主键
            ResultSet rsKey = connection.getMetaData().getPrimaryKeys(connection.getCatalog().toUpperCase(),
                    null, tableName.toUpperCase());
            // 适用oracle,mysql
            // rs =conn.getMetaData().getPrimaryKeys(conn.getCatalog().toUpperCase(),conn.getMetaData().getUserName().toUpperCase(),tableName.toUpperCase());
            String tableKey="";
            while (rsKey.next()) {
                tableKey=tableKey+" "+rsKey.getString("COLUMN_NAME");
                //System.err.println("Table:"+tableName+"\t PK_NAME : "+ tableKey);
            }

            DatabaseTable table=new DatabaseTable(tableName,tableKey);
            //获取表里面有哪些列
            String sql="select * from "+tableName;
            PreparedStatement stmts=connection.prepareStatement(sql);
            ResultSet rs = stmts.executeQuery(sql);
            ResultSetMetaData data = rs.getMetaData();


          //  System.err.println("Table:"+tableName+"\t PK_NAME : "+ data.getColumnName(1));

            for (int i = 1; i <= data.getColumnCount(); i++) {
                // 获得指定列的列名
                String columnName = data.getColumnName(i);
                // 获得指定列的数据类型名
                String columnTypeName = data.getColumnTypeName(i);
                // 对应数据类型的类
                //String columnClassName = data.getColumnClassName(i);
                // 在数据库中类型的最大字符个数
                int columnDisplaySize = data.getColumnDisplaySize(i);
                DatabaseColumn databaseColumn=new DatabaseColumn(columnName,columnTypeName,columnDisplaySize);
                table.setColumns(databaseColumn);



                //System.out.println("获得列" + i + "的字段名称:" + columnName);
                //System.out.println("获得列" + i + "的数据类型名:" + columnTypeName);
                //System.out.println("获得列" + i + "在数据库中类型的最大字符个数:"+ columnDisplaySize);
            }
            tableNames.add(table);
            //System.out.println(tableName.length());
        }
        return  tableNames;
    }





        //表比较
    public static void compareTables() throws Exception{
        // 旧数据库连接
        Connection oldConn=getOldTable();
        List<DatabaseTable> getOldDbTables=getDbTables(oldConn);

        /* 新数据库连接 */
        Connection newConn=getNewTable();
        List<DatabaseTable> getNewDbTables=getDbTables(newConn);
            //新库数据表名组合
            List<String> tablenames=new ArrayList<String>();
            for (DatabaseTable  newTable: getNewDbTables){
                tablenames.add(newTable.getTableName());
            }
            //旧库数据表名组合
            List<String> oleTablenames=new ArrayList<String>();
            for (DatabaseTable  oldTable: getOldDbTables){
                oleTablenames.add(oldTable.getTableName());
            }
            //查看旧库所有表是否在新库里面都有（新库就不用查旧库是否存在了）
            for(DatabaseTable  oldTable: getOldDbTables){
                if (!tablenames.contains(oldTable.getTableName())) {
                    //说明新库里面没有这个表
                    append(oldTable, null, 1);
                }
            }
            //查看旧库所有表是否在新库里面都有（新库就不用查旧库是否存在了）
            for(DatabaseTable  newTable: getNewDbTables){
                if (!oleTablenames.contains(newTable.getTableName())) {
                    //说明旧库里面没有这个表
                    append(newTable, null, 2);
                }
            }


        //比较两个表的字段类型
        for (int i=0;i<getOldDbTables.size();i++){
            for (int j=0;j<getNewDbTables.size();j++){
                DatabaseTable newTable=getNewDbTables.get(j);
                DatabaseTable oldTable=getOldDbTables.get(i);
                //保证两张表一样才去执行
                if (newTable.getTableName().equals(oldTable.getTableName())){
                    System.out.println("新表"+newTable.getTableName()+"\t 新表key"+newTable.tableKey);
                    System.out.println("旧表"+oldTable.getTableName()+"\t 旧表key"+oldTable.tableKey);
                    if (!newTable.tableKey.equals(oldTable.getTableKey())){
                        //说明两个主键不一致6
                        System.out.println("两表值不一致");
                        append(newTable, null, 7);
                    }

                    List<DatabaseColumn> newColumList=newTable.getColumns();
                    List<DatabaseColumn> oldColumList=oldTable.getColumns();
                        //新库数据表名下字段组合
                        List<String> newColums=new ArrayList<String>();
                        for (DatabaseColumn  newColumn: newColumList){
                            newColums.add(newColumn.getColumnName());
                        }
                        //旧库数据表名下字段组合
                        List<String> oldColums=new ArrayList<String>();
                        for (DatabaseColumn  oldColumn: oldColumList){
                            oldColums.add(oldColumn.getColumnName());
                        }

                        //查看旧库所有表是否在新库里面都有（新库就不用查旧库是否存在了）
                        for(String  oldColumn: oldColums){
                            if (!newColums.contains(oldColumn)) {
                                //说明新库表里面没有这个字段
                                int index=oldColums.indexOf(oldColumn);
                                append(oldTable, oldTable.getColumns().get(index), 3);
                            }else{
                                int index=newColums.indexOf(oldColumn);
                                String newColumType=newColumList.get(index).getDataType();
                                int    newColumLen=newColumList.get(index).getLength();
                                int oldIndex=oldColums.indexOf(oldColumn);
                                String oldColumType=oldColumList.get(oldIndex).getDataType();
                                int    oldColumLen=oldColumList.get(oldIndex).getLength();
                                if(!newColumType.equals(oldColumType)){
                                    //说明字段类型不一致
                                    append(newTable, oldColumList.get(index), 5);
                                }else if(newColumLen!=oldColumLen){
                                    //说明字类长度不一致
                                    append(newTable, oldColumList.get(index), 6);
                                }

                            }
                        }
                    //查看旧库所有表是否在新库里面都有
                    for(String  newColumn: newColums){
                        if (!oldColums.contains(newColumn)) {
                            //说明旧库表里面没有这个字段
                            int index=newColums.indexOf(newColumn);
                            append(newTable, newTable.getColumns().get(index), 4);
                        }
                    }




                }



            }


        }


    }

    /**
     * 写入错误的信息
     * @param table
     * @param column
     * @param flag
     * @throws Exception
     */
    public static void append(DatabaseTable table, DatabaseColumn column, int flag)
            throws Exception {
        switch (flag) {
            case 1:
                System.out.println("1、查看旧库表存在，而新库表不存在的表名有：" + table.getTableName());// 跳过
                sbMessage.append("1、查看旧库表存在，而新库表不存在的表名有：" + table.getTableName()+ "\n");
                //sb[0].append(table.getTableName() + "\n");
                break;
            case 2:
                System.out.println("2、查看新库表存在，而旧库表不存在的表名有：" + table.getTableName());//
                sbMessage.append("2、查看新库表存在，而旧库表不存在的表名有：" + table.getTableName()+ "\n");
                //sb[1].append(table.getTableName() + "\n");
                break;
            case 3:
                System.out.println("3、旧库表：【"+table.getTableName()+"】中的字段：【"+column.getColumnName()+"】在新库表中不存在.");// 需人工判断如何处理
                sbMessage.append("3、旧库表：【"+table.getTableName()+"】中的字段：【"+column.getColumnName()+"】在新库表中不存在."+ "\n");
                // sb[2].append(table.getTableName() + " | " + column.getColumnName() + "\n");
                break;
            case 4:
                System.out.println("4、新库表：【"+table.getTableName()+"】中的字段：【"+column.getColumnName()+"】在旧库表中不存在.");// 需人工判断如何处理
                sbMessage.append("4、新库表：【"+table.getTableName()+"】中的字段：【"+column.getColumnName()+"】在旧库表中不存在."+"\n");
                //sb[2].append(table.getTableName() + " | " + column.getColumnName()+ "\n");
                break;
            case 5:
                System.out.println("5、表【" + table.getTableName()+"】在新旧库中,字段【"+column.getColumnName()+"】类型不一致");// 需要人工判断脚本
                sbMessage.append("5、表【" + table.getTableName()+"】在新旧库中,字段【"+column.getColumnName()+"】类型不一致"+"\n");
                //sb[4].append(table.getTableName() + " | " + column.getColumnName()+ "\n");
                break;
            case 6:
                System.out.println("6、表【"+table.getTableName()+"】和字段【"+column.getColumnName()+"】字段类型都相同，但字段长度不同的内容："+ column.getLength());// 需要人工判断脚本
                sbMessage.append("6、表【"+table.getTableName()+"】和字段【"+column.getColumnName()+"】字段类型都相同，但字段长度不同的内容："+ column.getLength()+"\n");
                // sb[5].append(table.getTableName() + " | " + column.getColumnName()+ " | " + column.getLength() + "\n");
                break;
            case 7:
                System.out.println("7、新表【"+table.getTableName()+"】跟旧表【"+table.getTableName()+"】的主键【"+table.getTableKey()+"】不一致\n");// 需要人工判断脚本
                sbMessage.append("7、新旧表【"+table.getTableName()+"】跟旧表【"+table.getTableName()+"】的主键【"+table.getTableKey()+"】不一致\n");
                // sb[6].append(table.getTableName() + " | " + column.getColumnName()+ " | " + column.getLength() + "\n");
                break;
        }
    }

    public static void writeFile() throws Exception {
        FileWriter fw=new FileWriter("D:/test.txt");
        fw.write(sbMessage.toString());
        fw.close();
    }

}
